﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using itau.im.relatorios.entidade;
using itau.im.relatorios.dado;
using EnterpriseLibraryWrapper;

namespace itau.im.relatorios.negocio
{
    public class RelatorioProdutoBS : IRelatorioProdutoBS
    {
        public FiltroRelatorioProduto ObterFiltrosRelatorioProduto()
        {
            IRelatorioProdutoDAO relatorioProdutoDAO = null;
            IRelatorioGrupoParametroDAO relatorioGrupoParametroDAO = null;
            FiltroRelatorioProduto filtroRelatorioProduto = null;

            try
            {
                relatorioProdutoDAO = DaoFactory.getRelatorioProduto();
                relatorioGrupoParametroDAO = DaoFactory.getRelatorioGrupoParametro();

                filtroRelatorioProduto = new FiltroRelatorioProduto();
                filtroRelatorioProduto.Classe = relatorioProdutoDAO.ObterClassesProdutoFinanceiro();
                filtroRelatorioProduto.Familia = relatorioProdutoDAO.ObterFamiliasProdutoFinanceiro();
                filtroRelatorioProduto.Produto = relatorioProdutoDAO.ObterProdutosFinanceiros();
                filtroRelatorioProduto.GrupoParametro = relatorioGrupoParametroDAO.ObterGruposParametros();

                List<ProdutoFinanceiroDerivado> listaProdutoDerivado = new List<ProdutoFinanceiroDerivado>();
                foreach (ProdutoFinanceiro itemProduto in filtroRelatorioProduto.Produto)
                {
                    listaProdutoDerivado.AddRange(relatorioProdutoDAO.ObterProdutosDerivadosPorProduto(itemProduto.CodigoProdutoFinanceiro));
                }
                filtroRelatorioProduto.ProdutoDerivado = listaProdutoDerivado;

                List<ProdutoFinanceiroAlocacao> listaProdutoAlocacao = new List<ProdutoFinanceiroAlocacao>();
                foreach (GrupoParametro itemGrupo in filtroRelatorioProduto.GrupoParametro)
                {
                    listaProdutoAlocacao.AddRange(relatorioGrupoParametroDAO.ObterProdutoFinanceiroAlocacaoPorGrupoParametro(itemGrupo.CodigoGrupoParametro));
                }
                filtroRelatorioProduto.ProdutoAlocacao = listaProdutoAlocacao;

                return filtroRelatorioProduto;
            }
            catch (DadosException ex)
            {
                EnterpriseLibraryFactory.GetExceptionHandler().HandleException(ex, "ErrosNegocios");
            }
            catch (NegociosException ex)
            {
                EnterpriseLibraryFactory.GetExceptionHandler().HandleException(ex, "ErrosNegocios");
            }
            catch (Exception ex)
            {
                EnterpriseLibraryFactory.GetExceptionHandler().HandleException(ex, "ErrosNegocios");
            }
            finally
            {
                relatorioProdutoDAO = null;
            }

            return filtroRelatorioProduto;
        }

        public IList<RelatorioSubProdPorGrupoParamSaida> ConsultarRelatorioSubProdPorGrupoParam(RelatorioSubProdPorGrupoParamEntrada filtroRelatorio)
        {
            IRelatorioParametroDAO relatorioParametroDAO = null;
            IRelatorioProdutoDAO relatorioProdutoDAO = null;
            IRelatorioRegraDAO relatorioRegraDAO = null;
            IRelatorioGrupoParametroDAO relatorioGrupoParametroDAO = null;
            IRelatorioCurvaDAO relatorioCurvaDAO = null;

            IList<RelatorioSubProdPorGrupoParamSaida> relatorioSubProdPorGrupoParamSaida = null;

            IList<Curva> listaCurvas;
            IList<ParametroAtribuicao> listaParametros;

            try
            {
                relatorioSubProdPorGrupoParamSaida = new List<RelatorioSubProdPorGrupoParamSaida>();

                relatorioParametroDAO = DaoFactory.getRelatorioParametro();
                relatorioProdutoDAO = DaoFactory.getRelatorioProduto();
                relatorioRegraDAO = DaoFactory.getRelatorioRegra();
                relatorioGrupoParametroDAO = DaoFactory.getRelatorioGrupoParametro();
                relatorioCurvaDAO = DaoFactory.getRelatorioCurva();

                listaCurvas = relatorioCurvaDAO.ObterCurvas();
                listaParametros = relatorioParametroDAO.ObterParametros();

                foreach (GrupoParametro itemGrupo in filtroRelatorio.ListaGrupoParametro)
                {
                    IList<RegraAtribuicaoCurva> regrasPorGrupo = relatorioRegraDAO.ObterRegrasAtribuicaoCurvaPorCodigoGrupoData(itemGrupo.CodigoGrupoParametro, filtroRelatorio.DataInicioVigencia, filtroRelatorio.DataFimVigencia);
                    IList<DominioParametroAtribuicao> dominiosPorGrupo = relatorioParametroDAO.ObterDominiosParametrosAtribuicaoPorGrupoVigente(itemGrupo.CodigoGrupoParametro);
                    IList<ParametroAtribuicaoGrupoAlocacao> parametrosEndogenosPorGrupo = relatorioParametroDAO.ObterParametrosAtribuicaoGrupoAlocacaoPorGrupoParametrosVigente(itemGrupo.CodigoGrupoParametro);
                    IList<ProdutoFinanceiroDerivado> produtosExcecaoPorGrupo = relatorioProdutoDAO.ObterProdutosFinanceirosDerivadosExcecaoPorGrupoParametrosVigente(itemGrupo.CodigoGrupoParametro);

                    foreach (RegraAtribuicaoCurva itemRegra in regrasPorGrupo)
                    {
                        //Trata apenas as regras com SubProduto de Exceção listado no filtro SubProdutos
                        //if (filtroRelatorio.ListaProdutoAlocacao.Exists(p => p.CodigoProdutoFinanceiroDerivado == itemRegra.CodigoProdutoFinanceiroExcecao))
                        {
                            RelatorioSubProdPorGrupoParamSaida novoItemRelatorio = new RelatorioSubProdPorGrupoParamSaida();
                            novoItemRelatorio.ListaParametros = new List<ParametroRelatorio>();

                            IList<ParametroRegra> parametrosPorRegra = relatorioParametroDAO.ObterParametroAtribuicaoPorRegraDataVigencia(itemRegra.CodigoRegraAtribuicaoCurva, itemRegra.DataInicioVigencia);
                            IEnumerable<ParametroRegra> parametrosExogenosPorRegra = parametrosPorRegra.Where(p => parametrosEndogenosPorGrupo.Count(q => q.CodigoParametroAtribuicao == p.CodigoParametroAtribuicao) == 0);

                            Curva primeiraCurva = listaCurvas.FirstOrDefault(p => p.CodigoCurva == itemRegra.CodigoCurvaPrimeira);
                            Curva primeiraCurvaCaixa = listaCurvas.FirstOrDefault(p => p.CodigoCurva == itemRegra.CodigoCurvaPrimeiraComCaixa);
                            Curva terceiraCurva = listaCurvas.FirstOrDefault(p => p.CodigoCurva == itemRegra.CodigoCurvaTerceira);
                            Curva terceiraCurvaCaixa = listaCurvas.FirstOrDefault(p => p.CodigoCurva == itemRegra.CodigoCurvaTerceiraComCaixa);
                            ProdutoFinanceiroDerivado produtoExcecao = produtosExcecaoPorGrupo.FirstOrDefault(p => p.CodigoProdutoFinanceiroDerivado == itemRegra.CodigoProdutoFinanceiroExcecao);

                            novoItemRelatorio.NomeCurva = primeiraCurva != null ? primeiraCurva.NomeCurva : string.Empty;
                            novoItemRelatorio.NomeCurvaComCaixa = primeiraCurvaCaixa != null ? primeiraCurvaCaixa.NomeCurva : string.Empty;
                            novoItemRelatorio.NomeTerceiraCurva = terceiraCurva != null ? terceiraCurva.NomeCurva : string.Empty;
                            novoItemRelatorio.NomeTerceiraCurvaComCaixa = terceiraCurva != null ? terceiraCurva.NomeCurva : string.Empty;
                            novoItemRelatorio.NomeGrupoParametro = itemGrupo.NomeGrupoParametro;
                            novoItemRelatorio.NomeProdutoExcecao = produtoExcecao != null ? produtoExcecao.NomeProdutoFinanceiroDerivado : string.Empty;
                            novoItemRelatorio.Situacao = itemRegra.CodigoSituacao == 1 ? "Habilitada" : "Desabilitada";
                            novoItemRelatorio.DataInicioVigencia = itemRegra.DataInicioVigencia;
                            novoItemRelatorio.DataFimVigencia = itemRegra.DataFimVigencia;

                            foreach (var itemEndogeno in parametrosEndogenosPorGrupo)
                            {
                                ParametroAtribuicao parametroCompleto = listaParametros.FirstOrDefault(p => p.CodigoParametroAtribuicao == itemEndogeno.CodigoParametroAtribuicao);

                                novoItemRelatorio.ListaParametros.AddRange(ObterParametroEndogeno(itemEndogeno, parametroCompleto, dominiosPorGrupo));
                            }

                            foreach (var itemExogeno in parametrosExogenosPorRegra)
                            {
                                ParametroAtribuicao parametroCompleto = listaParametros.FirstOrDefault(p => p.CodigoParametroAtribuicao == itemExogeno.CodigoParametroAtribuicao);

                                IList<DominioParametroAtribuicao> dominioPorParametro = relatorioParametroDAO.ObterRegistrosDominioParametro(itemExogeno.CodigoParametroAtribuicao);

                                novoItemRelatorio.ListaParametros.AddRange(ObterParametroExogeno(itemExogeno, parametroCompleto, dominioPorParametro));
                            }

                            relatorioSubProdPorGrupoParamSaida.Add(novoItemRelatorio);
                        }
                    }
                }

                return relatorioSubProdPorGrupoParamSaida;
            }
            catch (DadosException ex)
            {
                EnterpriseLibraryFactory.GetExceptionHandler().HandleException(ex, "ErrosNegocios");
            }
            catch (NegociosException ex)
            {
                EnterpriseLibraryFactory.GetExceptionHandler().HandleException(ex, "ErrosNegocios");
            }
            catch (Exception ex)
            {
                EnterpriseLibraryFactory.GetExceptionHandler().HandleException(ex, "ErrosNegocios");
            }
            finally
            {
                relatorioProdutoDAO = null;
            }

            return relatorioSubProdPorGrupoParamSaida;
        }

        private IList<ParametroRelatorio> ObterParametroEndogeno(ParametroAtribuicaoGrupoAlocacao parametroAlocado, ParametroAtribuicao parametroCompleto, IList<DominioParametroAtribuicao> dominios)
        {
            IList<ParametroRelatorio> parametroRelatorio = new List<ParametroRelatorio>();

            if (parametroAlocado != null && parametroCompleto != null)
            {
                if (parametroAlocado.CodigoDominioParametroAtribuicao != 0)
                {
                    DominioParametroAtribuicao dominioDefinido = dominios.FirstOrDefault(p => p.CodigoDominioParametroAtribuicao == parametroAlocado.CodigoDominioParametroAtribuicao);

                    if (dominioDefinido != null)
                    {
                        parametroRelatorio.Add(new ParametroRelatorio()
                        {
                            Valor = dominioDefinido.TextoValorDominioParametro,
                            NomeParametro = parametroCompleto.NomeParametroAtribuicao
                        });
                    }
                }
                else
                {
                    if (string.IsNullOrEmpty(parametroAlocado.TextoValorAtribuicaoFim) &&
                        string.IsNullOrEmpty(parametroAlocado.TextoValorAtribuicaoFim.Trim())) //Parâmetro sem range
                    {
                        parametroRelatorio.Add(new ParametroRelatorio()
                        {
                            Valor = parametroAlocado.TextoValorParametroAtribuicao,
                            NomeParametro = parametroCompleto.NomeParametroAtribuicao
                        });
                    }
                    else //Parâmetro com range
                    {
                        parametroRelatorio.Add(new ParametroRelatorio()
                        {
                            Valor = parametroAlocado.TextoValorParametroAtribuicao,
                            NomeParametro = string.Concat(parametroCompleto.NomeParametroAtribuicao, " - ", "Início")
                        });

                        parametroRelatorio.Add(new ParametroRelatorio()
                        {
                            Valor = parametroAlocado.TextoValorAtribuicaoFim,
                            NomeParametro = string.Concat(parametroCompleto.NomeParametroAtribuicao, " - ", "Fim")
                        });
                    }
                }
            }

            return parametroRelatorio;
        }

        private IList<ParametroRelatorio> ObterParametroExogeno(ParametroRegra parametroAlocado, ParametroAtribuicao parametroCompleto, IList<DominioParametroAtribuicao> dominios)
        {
            IList<ParametroRelatorio> parametroRelatorio = new List<ParametroRelatorio>();

            if (parametroAlocado != null && parametroCompleto != null)
            {
                if (parametroAlocado.CodigoDominioParametroAtribuicao != 0)
                {
                    DominioParametroAtribuicao dominioSelecionado = dominios.FirstOrDefault(
                        p => p.CodigoDominioParametroAtribuicao == parametroAlocado.CodigoDominioParametroAtribuicao);

                    parametroRelatorio.Add(new ParametroRelatorio()
                    {
                        Valor = dominioSelecionado.TextoValorDominioParametro,
                        NomeParametro = parametroCompleto.NomeParametroAtribuicao
                    });
                }
                else
                {
                    if (string.IsNullOrEmpty(parametroAlocado.TextoValorInternoFim) &&
                        string.IsNullOrEmpty(parametroAlocado.TextoValorInternoFim.Trim())) //Parâmetro sem range
                    {
                        parametroRelatorio.Add(new ParametroRelatorio()
                        {
                            Valor = parametroAlocado.TextoValorInterno,
                            NomeParametro = parametroCompleto.NomeParametroAtribuicao
                        });
                    }
                    else //Parâmetro com range
                    {
                        parametroRelatorio.Add(new ParametroRelatorio()
                        {
                            Valor = parametroAlocado.TextoValorInterno,
                            NomeParametro = string.Concat(parametroCompleto.NomeParametroAtribuicao, " - ", "Início")
                        });

                        parametroRelatorio.Add(new ParametroRelatorio()
                        {
                            Valor = parametroAlocado.TextoValorInternoFim,
                            NomeParametro = string.Concat(parametroCompleto.NomeParametroAtribuicao, " - ", "Fim")
                        });
                    }
                }
            }

            return parametroRelatorio;
        }
    }
}
